#include "SessionClientSurServeur.h"


SessionClientSurServeur::SessionClientSurServeur(const GereClient &client)
{
    this->client = client;
    this->sock = client.socket;
    this->connecte = false;
    this->typeClient = 0;
    this->createurDeLaSalle = false;
    this->assist = false;
    cout<<"Session client construite.\n";
    cout<<"sin_addr : "<<client.addresse.sin_addr.s_addr<<"\n";
    cout<<"sin_port : "<<client.addresse.sin_port<<"\n";
}

void SessionClientSurServeur::setAssist(bool what)
{
    assist = what;
}

bool SessionClientSurServeur::getAssist()
{
    return assist;
}

void SessionClientSurServeur::setAssist_t(SessionClientSurServeur *session)
{
    assistant_te = session;
}

void SessionClientSurServeur::gere()
{
    cout<<"Fonction gere.\n";
    int idMessage;
    string chaine;
    list<string> liste;
    int encore = 1;
    while(encore)
    {
        idMessage = lireEntierUnOctet();
        if(idMessage == 0)
        {
            break;
        }
        if(idMessage == -1)
        {
            if(errno != EAGAIN)
            {
                cout<<"Erreur socket (non EAGAIN)\n";
                encore = 0;
            }
        }
        else
        {
            cout<<"Message recu sur le serveur : "<<idMessage<<endl;

            switch(idMessage)
            {
            case ETUD_LOGIN :
                {
                    chaine = lireChaine();
                    cout<<chaine<<'\n';
                    if(typeClient == 0 && login == "") // Controle si le client n'a pas déja un login.
                    {
                        // lock mutex
                        if(client.serveur->ajouterLogin(chaine, this))
                        {
                            cout<<"Pseudo "<<chaine<<" accepté.\n";
                            login = chaine;
                            typeClient = ETUDIANT;
                            cout<<chaine<<" ajouté à la liste des client (map)\n";
                            ecrireMessage(ETUD_LISTE, client.serveur->getListeSalles());
                            connecte = true;
                        }
                        else
                        {
                            cout<<"Pseudo "<<chaine<<" refusé.\n";
                            ecrireMessage(ETUD_ERR_LOGIN);
                            encore = 0;
                        }
                        // unlock mutex
                    }
                    break;
                }
            case ETUD_CHOIX_SALLE :
                {
                    chaine = lireChaine();
                    cout<<chaine<<"\n";
                    // On controle si le client est un étudiant et si il ne s'est pas déja connecté dans une salle.
                    if(typeClient == ETUDIANT && dansSalle == "")
                    {
                        if(client.serveur->dispoSalle(chaine))
                        {
                            cout<<"Salle "<<chaine<<" disponible.\n";
                            dansSalle = chaine;
                            //client.serveur->getListeActivites(dansSalle)->affiche();
                            ecrireMessage(ETUD_OK_CHOISALLE, client.serveur->getListeActivites(dansSalle));
                        }
                        else
                        {
                            cout<<"Salle "<<chaine<<" indisponible.\n";
                            ecrireMessage(ETUD_ERR_CHOIXSALLE);
                        }
                    }

                    break;
                }
            case ETUD_CHOIX_ACTIVITE :
                {
                    chaine = lireChaine();
                    cout<<chaine<<"\n";
                    // On verifie le type du client, si il est dans une salle et si il n'est pas en cours d'activité.
                    if(typeClient == ETUDIANT && dansSalle != "" && dansActivite == "")
                    {
                        list<string> listeAct = client.serveur->getListeActivites(dansSalle);
                        while(listeAct.size() > 0 && dansActivite == "")
                        {
                            if(listeAct.front() == chaine) dansActivite = chaine;
                            else listeAct.pop_front();
                        }
                        if(dansActivite != "") // Si l'activité demandée est activée.
                        {
                            ecrireMessage(ETUD_OK_CHOIX_ACTIVITE);
                            // Message a envoyer a tout les OBS !!!!!!!!!!!!!!!!!
                            list<string> listeObs  = client.serveur->getListeObsDansSalle(dansSalle);
                            int nbObs = listeObs.size();
                            cout<<"nbObs: "<<nbObs<<"\n";
                            cout<<listeObs.front()<<endl;
                            for(int i = 0; i < nbObs; ++i)
                            {
                                SessionClientSurServeur* obs  = client.serveur->getSessionClient(listeObs.front());
                                cout<<"coucou !!\n";
                                obs->ecrireMessage(ETUD_CHOIX_ACTIVITE_, login, dansSalle, dansActivite);
                                listeObs.pop_front();
                            }
                            if(dansActivite == "QCM")
                            {
                                qcm = client.serveur->qcm;
                                list<QuestionQCM>::iterator it = qcm.begin();
                                if(it != qcm.end()) // Si il reste encore des questions.
                                {
                                    QuestionQCM questionQCM = (*it);
                                    /*
                                    ListeChaines liste(questionQCM.reponses.size());
                                    list<string>::iterator it2 = questionQCM.reponses.begin();
                                    for(int i = 0; i < liste.nbChaines; ++i)
                                    {
                                        char* rep = new char[(*it2).size()];
                                        strcpy(rep, (*it2).c_str());
                                        liste.ajouter(i, rep);
                                        delete []rep;
                                        ++it2;
                                    }
                                    char* ques = new char[(*it).question.size()];
                                    strcpy(ques, (*it).question.c_str());
                                    */
                                    ecrireMessage(ETUD_QCM, questionQCM.question, questionQCM.reponses);
                                }
                                else // Si c'est la fin de l'activité.
                                {
                                    ecrireMessage(ETUD_FIN_ACTIVITE);
                                }
                            }
                        }
                        else // Si l'activité demandée n'est pas activée.
                        {

                        }
                    }
                    break;
                }
            case ETUD_REP_QCM :
                {
                    liste = lireListeChaines();
                    if(dansActivite == "QCM")
                    {
                        // Message a envoyer a tout les OBS !!!!!!!!!!!!!!!!!
                        list<string> listeObs  = client.serveur->getListeObsDansSalle(dansSalle);
                        int nbObs = listeObs.size();
                        QuestionQCM questionQCM = qcm.front(); // La question auquelle l'étu vient de répondre.
                        for(int i = 0; i < nbObs; ++i)
                        {
                            SessionClientSurServeur* obs  = client.serveur->getSessionClient(listeObs.front());
                            obs->ecrireMessage(ETUD_OBS_REP_QCM, login, questionQCM.question, liste);
                            listeObs.pop_front();
                        }
                        qcm.pop_front(); // On retire la question répondue de la liste des questions du QCM.

                        // On envoye la question suivante.
                        list<QuestionQCM>::iterator it = qcm.begin();
                        if(it != qcm.end()) // Si il reste encore des questions.
                        {
                            QuestionQCM questionQCM = (*it);
                            /*
                            ListeChaines liste(questionQCM.reponses.size());
                            list<string>::iterator it2 = questionQCM.reponses.begin();
                            for(int i = 0; i < liste.nbChaines; ++i)
                            {
                                char* rep = new char[(*it2).size()];
                                strcpy(rep, (*it2).c_str());
                                liste.ajouter(i, rep);
                                delete []rep;
                                ++it2;
                            }
                            char* ques = new char[(*it).question.size()];
                            strcpy(ques, (*it).question.c_str());
                            */
                            ecrireMessage(ETUD_QCM, questionQCM.question, questionQCM.reponses);
                        }
                        else // Si c'est la fin de l'activité.
                        {
                            ecrireMessage(ETUD_FIN_ACTIVITE);
                            dansActivite = "";
                            qcm.clear();
                        }
                    }
                    break;
                }
            case ETUD_AST_MSG :
                {
                    chaine = lireChaine();
                    if(typeClient == ETUDIANT && assist)
                    {
                        assistant_te->ecrireMessage(ETU_MSG, chaine);
                    }
                    break;
                }
            case OBS_LOGIN : {
                    chaine = lireChaine();
                    cout<<chaine<<'\n';
                    if(typeClient == 0 && login == "") // Controle si le client n'a pas déja un login.
                    {
                        // lock mutex
                        if(client.serveur->ajouterLogin(chaine, this))
                        {
                            cout<<"Pseudo "<<chaine<<" accepté.\n";
                            login = chaine; // NOUVEAU
                            typeClient = OBSERVATEUR;
                            cout<<chaine<<" ajouté à la liste des clients (map)\n";
                            ecrireMessage(OBS_LISTE, client.serveur->getListeSalles());
                            connecte = true;
                        }
                        else
                        {
                            cout<<"Pseudo "<<chaine<<" refusé.\n";
                            ecrireMessage(OBS_ERR_LOGIN);
                        }
                        // unlock mutex
                    }
                    break;
                }
            case OBS_CHOIX : {
                    //L'observateur s'est connecte a une salle deja existante.
                    //Il faut envoyer la liste des activites de cette salle.
                    chaine = lireChaine(); // La salle qu'il a choisie
                    cout<<chaine<<"\n";
                    if(typeClient == OBSERVATEUR && dansSalle == "") // message cohérent.
                    {
                        if(chaine == "") ecrireMessage(OBS_ERR_CHOIX); // Si nom de salle vide on envoye une erreur.
                        else
                        {
                            if(client.serveur->dispoSalle(chaine)) // Connexion à une salle déja ouverte.
                            {
                                cout<<"Salle "<<chaine<<" disponible.\n";
                                dansSalle = chaine;
                                client.serveur->ajouterObsDansSalle(dansSalle, login);
                                ecrireMessage(OBS_OK_CHOIX);
                            }
                            else // Ouverture d'une nouvelle salle.
                            {
                                cout<<"Salle "<<chaine<<" créée.\n";
                                client.serveur->ajouterSalle(chaine);
                                createurDeLaSalle = true;
                                dansSalle = chaine;
                                client.serveur->ajouterObsDansSalle(dansSalle, login);
                                //  ecrireMessage(OBS_OK_CHOIX);   //  COMPATIBILITE PROTO
                                ecrireMessage(OBS_OK_CHOIX_SALLE_CREE); //  COMPATIBILITE PROTO
                            }
                        }
                    }
                    break;
                }
                /*
            case OBS_CHOIX_NVELLE_SALLE : {
                    cout<<"OBS_CHOIX_NOUVELLE_SALLE"<<endl;
                    //L'observteur demande l'ouverture d'une salle.
                    chaine = lireChaine();
                    client.serveur->ajouterSalle(chaine);
                    dansSalle = chaine;
                    //client.serveur->ajouterObsDansSalle(chaine, login);
                    ecrireMessage(OBS_OK_CHOIX_SALLE_CREE,client.serveur->getListeSalles());
                    tmp = chaine;
                    break;
                }
                */
            case OBS_ACTIVITES :
                {
                    cout<<"OBS_ATIVITES"<<endl;
                    liste = lireListeChaines(); //Lecture de la liste des activites.
                    if(typeClient == OBSERVATEUR && createurDeLaSalle) // message cohérent.
                    {
                        cout<<"Activites Recues : ";
                        client.serveur->ajouterActivites(dansSalle, liste);
                        ecrireMessage(OBS_ACTIVITE_OK, client.serveur->getListeActivites(dansSalle));
                    }
                    break;
                }
            case AST_LOGIN :
                {
                    string astLogin = lireChaine();
                    string etuLogin = lireChaine();
                    cout<<"Login etu : "<<etuLogin<<"\n";
                    cout<<"Login ast : "<<astLogin<<"\n";
                    SessionClientSurServeur* session = client.serveur->getSessionClient(etuLogin);
                    if(session)
                    {
                        if(typeClient == OBSERVATEUR && !assist && !session->getAssist()) // Assistance possible.
                        {
                            session->setAssist(true);
                            session->setAssist_t(this);
                            assist = true;
                            assistant_te = session;
                            ecrireMessage(AST_OK_LOGIN);
                        }
                        else // Assistance non possible.
                        {
                            ecrireMessage(AST_ERR_LOGIN);
                        }
                    }
                    else
                    {
                        cout<<"DTC !!\n";
                        ecrireMessage(AST_ERR_LOGIN);
                    }
                    break;
                }
            case AST_LOGOUT :
                {
                    if(typeClient == OBSERVATEUR && assist)
                    {
                        assist  = false;
                        assistant_te->setAssist(false);
                        assistant_te = NULL;
                    }
                    break;
                }
            case AST_ETUD_MSG :
                {
                    chaine = lireChaine();
                    if(typeClient == OBSERVATEUR && assist)
                    {
                        assistant_te->ecrireMessage(AST_MSG, chaine);
                    }
                    break;
                }
            }
        }
    }
    client.serveur->enleverLogin(login);
    if(dansSalle != "" && typeClient == OBSERVATEUR) client.serveur->enleverObsDansSalle(dansSalle, login);
    if(dansSalle != "" && typeClient == ETUDIANT) client.serveur->enleverEtuDansSalle(dansSalle, login);
    if(assist)
    {
        assistant_te->setAssist(false);
        assistant_te->setAssist_t(0);
    }
}

int SessionClientSurServeur::getTypeClient()
{
    return typeClient;
}

string SessionClientSurServeur::getDansSalle()
{
    return dansSalle;
}

string SessionClientSurServeur::getDansActivite()
{
    return dansActivite;
}
